//! 闭包 (Closures)
//!
//! 闭包是可以捕获其环境的匿名函数，是 Rust 中函数式编程的重要特性。
//! 它们可以作为参数传递给其他函数，赋值给变量，或存储在数据结构中。
//!
//! ## 知识点总结
//!
//! | 知识点 | 说明 |
//! |--------|------|
//! | 闭包语法 | 使用竖线`|args|`定义参数，如`|x| x + 1` |
//! | 捕获环境 | 闭包可以捕获其定义环境中的变量 |
//! | 闭包特性 | `Fn`、`FnMut`、`FnOnce`三种特性定义闭包的行为 |
//! | 闭包与函数 | 闭包可以作为函数参数传递 |
//! | 闭包与迭代器 | 闭包常与迭代器方法配合使用 |
//! | Move闭包 | 使用`move`关键字强制闭包获取环境变量的所有权 |
//!
//! ## 闭包使用场景对比
//!
//! | 场景 | 闭包优势 | 函数优势 |
//! |------|---------|---------|
//! | 短小的一次性逻辑 | 语法简洁，可捕获环境 | 明确命名，可复用 |
//! | 迭代器适配器 | 自然结合，代码简洁 | 性能略好，类型明确 |
//! | 回调函数 | 可捕获上下文 | 无捕获开销 |
//! | 高阶函数 | 灵活，可定制行为 | 编译时确定，性能好 |
//! | 复杂逻辑复用 | 可以封装状态 | 更容易测试和文档化 |
//!
//! ## 闭包特性实现对比
//!
//! | 闭包特性 | 捕获方式 | 可调用次数 | 使用场景 |
//! |----------|----------|------------|----------|
//! | Fn | 不可变借用(&T) | 多次 | 只读访问环境变量 |
//! | FnMut | 可变借用(&mut T) | 多次 | 需要修改环境变量 |
//! | FnOnce | 获取所有权(T) | 一次 | 需要获取环境变量所有权 |

/// 1. 闭包基础语法
/// 闭包使用竖线(|)包围参数，后跟可选的返回类型注解和函数体
pub fn closure_basics() {
    println!("=== 闭包基础语法 ===");

    // 最简单的闭包，不捕获任何变量
    let simple_closure = || println!("这是一个简单的闭包");
    simple_closure();

    // 带参数的闭包
    let double = |x| x * 2;
    println!("5 的两倍是: {}", double(5));

    // 带类型注解的闭包
    let typed_closure = |x: i32| -> i32 { x * 2 };
    println!("6 的两倍是: {}", typed_closure(6));

    // 多参数闭包
    let add = |x, y| x + y;
    println!("3 + 4 = {}", add(3, 4));
}

/// 2. 闭包捕获变量
/// 闭包可以捕获其环境中的变量
pub fn closure_capture() {
    println!("\n=== 闭包捕获变量 ===");

    let x = 4;

    // 闭包捕获环境中的变量 x
    let equal_to_x = |z| z == x;

    let y = 4;
    assert!(equal_to_x(y));
    println!("{} 等于 {}: {}", y, x, equal_to_x(y));

    // 闭包可以修改可变捕获的变量
    let mut num = 5;
    {
        let mut add_num = |x: i32| num += x;
        add_num(5);
    }
    println!("num 现在是: {num}");
}

/// 3. 闭包与函数的区别
/// 闭包可以捕获环境变量，而函数不能
pub fn closure_vs_function() {
    println!("\n=== 闭包与函数的区别 ===");

    let x = 4;

    // 闭包可以捕获环境中的变量
    let equal_to_x_closure = |z| z == x;

    // 等效的函数无法直接访问 x
    fn equal_to_x_function(z: i32, x: i32) -> bool {
        z == x
    }

    let y = 4;
    println!("闭包: {} 等于 {}: {}", y, x, equal_to_x_closure(y));
    println!("函数: {} 等于 {}: {}", y, x, equal_to_x_function(y, x));
}

/// 4. 闭包的三种特性
/// 闭包根据其对环境变量的使用方式自动实现以下特性之一：
/// - Fn: 不可变借用捕获的变量
/// - FnMut: 可变借用捕获的变量
/// - FnOnce: 获取捕获变量的所有权
pub fn closure_traits() {
    println!("\n=== 闭包的三种特性 ===");

    let x = 5;

    // Fn: 不可变借用
    let printer = || println!("x 的值是: {x}");
    printer();
    printer(); // 可以多次调用

    // FnMut: 可变借用
    let mut y = 5;
    let mut mutator = || {
        y += 1;
        println!("y 的值是: {y}");
    };
    mutator();
    mutator();

    // FnOnce: 获取所有权
    let z = String::from("Hello");
    let taker = || {
        println!("获取所有权: {z}"); // z 的所有权被移动到闭包中
    };
    taker();
    // taker(); // 这会出错，因为 z 的所有权已经被移动了
}

/// 5. 闭包与迭代器结合使用
/// 闭包经常与迭代器一起使用，这是 Rust 中非常常见的模式
pub fn closure_with_iterators() {
    println!("\n=== 闭包与迭代器结合使用 ===");

    let v1 = vec![1, 2, 3, 4, 5];

    // 使用 map 和闭包
    let v2: Vec<i32> = v1.iter().map(|x| x + 1).collect();
    println!("原向量: {v1:?}");
    println!("加1后: {v2:?}");

    // 使用 filter 和闭包
    let v3: Vec<&i32> = v1.iter().filter(|x| **x > 3).collect();
    println!("大于3的元素: {v3:?}");

    // 使用 fold 和闭包
    let sum = v1.iter().fold(0, |acc, x| acc + x);
    println!("向量元素之和: {sum}");
}

/// 6. 闭包作为参数和返回值
/// 函数可以接受闭包作为参数，也可以返回闭包
pub fn closure_as_parameter_return() {
    println!("\n=== 闭包作为参数和返回值 ===");

    // 接受闭包作为参数
    fn apply<F>(f: F) -> i32
    where
        F: FnOnce() -> i32,
    {
        f()
    }

    let result = apply(|| 42);
    println!("应用闭包的结果: {result}");

    // 返回闭包
    fn make_adder(x: i32) -> impl Fn(i32) -> i32 {
        move |y| x + y
    }

    let add_5 = make_adder(5);
    println!("5 + 3 = {}", add_5(3));
}

/// 7. 闭包类型推断和注解
/// 闭包不需要像函数那样显式声明参数和返回值类型
pub fn closure_type_inference() {
    println!("\n=== 闭包类型推断和注解 ===");

    // 编译器可以推断类型
    let add_one = |x| x + 1;
    println!("5 + 1 = {}", add_one(5));

    // 显式类型注解
    let multiply = |x: i32, y: i32| -> i32 { x * y };
    println!("3 * 4 = {}", multiply(3, 4));

    // 注意：闭包的参数类型只能推断一次
    let example_closure = |x| x;
    let s = example_closure(String::from("hello"));
    // let n = example_closure(5); // 这会出错，因为编译器已经推断 x 为 String 类型
    println!("闭包返回值: {s}");
}

/// 8. 闭包与函数指针的对比
/// 闭包和函数指针都可以作为函数参数传递
pub fn closure_vs_function_pointer() {
    println!("\n=== 闭包与函数指针的对比 ===");

    // 函数
    fn add_one_v1(x: u32) -> u32 {
        x + 1
    }

    // 函数指针
    let add_one_v2: fn(u32) -> u32 = add_one_v1;

    // 闭包
    let add_one_v3 = |x: u32| -> u32 { x + 1 };

    println!("函数: {}", add_one_v1(5));
    println!("函数指针: {}", add_one_v2(5));
    println!("闭包: {}", add_one_v3(5));
}

/// 9. Move闭包
/// 使用move关键字强制闭包获取其环境变量的所有权
pub fn move_closures() {
    println!("\n=== Move闭包 ===");

    // 字符串向量，将被move闭包获取所有权
    let words = vec![String::from("rust"), String::from("closure"), String::from("move")];

    // 不使用move关键字的闭包，只会借用环境变量
    // let borrow_closure = || {
    //     for word in &words {  // 这里只是借用
    //         println!("{}", word);
    //     }
    // };
    // borrow_closure();
    // println!("在借用闭包之后，words仍然可用: {:?}", words); // 这行可以正常工作

    // 使用move关键字的闭包，获取环境变量的所有权
    let move_closure = move || {
        for word in &words {
            // words的所有权被移动到闭包中
            println!("Move闭包中的单词: {}", word);
        }
    };

    // 调用move闭包
    move_closure();

    // 在move闭包使用后，words不再可用
    // println!("在move闭包之后，words不再可用: {:?}", words); // 这行会编译错误

    // Move闭包与线程的结合使用
    println!("\n--- Move闭包与线程 ---");
    let greeting = String::from("Hello");
    let thread_closure = move || {
        println!("在线程中使用move闭包: {}", greeting);
        greeting
    };

    let handle = std::thread::spawn(thread_closure);
    let result = handle.join().unwrap();
    println!("从线程返回的结果: {}", result);

    // Move与闭包特性的关系
    println!("\n--- Move与闭包特性 ---");
    let data = vec![1, 2, 3];

    // 由于move闭包获取了data的所有权，它只能被调用一次（FnOnce）
    let once_closure = move || {
        println!("FnOnce闭包消费了数据: {:?}", data);
        data.len()
    };

    let length = once_closure();
    println!("数据的长度: {}", length);
    // once_closure(); // 这行会编译错误，因为闭包已经消费了数据
}

/// 主演示函数
pub fn demonstrate_closures() {
    closure_basics();
    closure_capture();
    closure_vs_function();
    closure_traits();
    closure_with_iterators();
    closure_as_parameter_return();
    closure_type_inference();
    closure_vs_function_pointer();
    move_closures(); // 添加move闭包演示
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_closure_basics() {
        closure_basics();
    }

    #[test]
    fn test_closure_capture() {
        closure_capture();
    }

    #[test]
    fn test_closure_vs_function() {
        closure_vs_function();
    }

    #[test]
    fn test_closure_traits() {
        closure_traits();
    }

    #[test]
    fn test_closure_with_iterators() {
        closure_with_iterators();
    }

    #[test]
    fn test_closure_as_parameter_return() {
        closure_as_parameter_return();
    }

    #[test]
    fn test_closure_type_inference() {
        closure_type_inference();
    }

    #[test]
    fn test_closure_vs_function_pointer() {
        closure_vs_function_pointer();
    }
}
